package com.itee.street.controller;

import com.itee.core.serial.SerialHandler;
import com.itee.core.serial.SerialPortFactory;
import com.itee.core.serial.SerialSession;
import com.itee.core.util.CalendarUtils;
import com.itee.core.util.GuiPrintStream;
import com.itee.core.util.StringCoder;
import com.itee.javafx.ExecutorsUtils;
import com.itee.javafx.controls.LimitedTextInputDialog;
import com.itee.monitor.BaseTestSession;
import com.itee.street.dialog.ImportFileDialog;
import com.itee.street.entity.LampData;
import com.itee.street.entity.Term;
import com.itee.street.excel.ExportXlsData;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.stage.FileChooser;
import org.controlsfx.dialog.Dialogs;

import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

public class Controller implements Initializable {

    private static final String CONCENT_UID = "000000000";

    @FXML
    public TextArea taLog;

    @FXML
    private TableView termTable;

    @FXML
    private TableColumn checkBoxColumn;

    @FXML
    private Spinner intervalSpinner;

    @FXML
    private Spinner dimmingSpinner;


    private ObservableList<Term> terms = FXCollections.observableArrayList();

    private void resetTermsPn() {
        for (int i = 0; i < terms.size(); i++) {
            terms.get(i).setPn(i + 2);
        }
    }

    private SerialHandler serialHandler;

    @FXML
    public void handleMouseAction(MouseEvent event) {
        if (event.getButton() == MouseButton.SECONDARY) {

        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // 重定向标准输出流和错误流到txtLog
        GuiPrintStream out = new GuiPrintStream(System.out, taLog, true);
        System.setOut(out);
        System.setErr(out);

        checkBoxColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkBoxColumn));
        SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 99);
        svf.setValue(5);
        intervalSpinner.setValueFactory(svf);

        SpinnerValueFactory svf1 = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
        svf1.setValue(10);
        dimmingSpinner.setValueFactory(svf1);
        termTable.setItems(terms);

        serialHandler = SerialHandler.getInstance();
    }

    @FXML
    public void handleAddAction(ActionEvent event) {
        LimitedTextInputDialog dlg = new LimitedTextInputDialog("");
        dlg.setTitle("新建终端");
        dlg.getDialogPane().setContentText("请输入终端UID：");
        dlg.showAndWait().ifPresent(result -> {
            if (result != null) {
                result = result.trim();
                if (result.length() > 0) {
                    String termUid = StringCoder.fillZeroLeft(result, 12);
                    if (!containTerm(termUid)) {
                        Term term = new Term();
                        term.setTermUid(termUid);
                        terms.add(term);
                    }
                    resetTermsPn();
                }
            }
        });
    }

    @FXML
    public void handleAddsAction(ActionEvent event) {
        ImportFileDialog fileDialog = new ImportFileDialog();
        fileDialog.showAndWait().ifPresent(response -> {
            List<Term> terms1 = (List<Term>) fileDialog.getResult();
            if (terms1 != null && terms1.size() > 0) {
                for (Term term : terms1) {
                    if (!containTerm(term.getTermUid())) {
                        terms.add(term);
                    }
                }
//                resetTermsPn();
            }
        });
    }

    @FXML
    public void handleExportAction(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("导出到Excel");
        SimpleDateFormat FORMAT_DATE_TIME = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
        fileChooser.setInitialFileName(CalendarUtils.formatDateByFormat(new Date(), FORMAT_DATE_TIME) + " terms.xls");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Excel Files", "*.xls"));
        File file = fileChooser.showSaveDialog(null);
        if (file != null) {
            ExportXlsData.exportExcel(terms, file.getAbsolutePath());
        }
    }

    @FXML
    public void handleCheckAction(ActionEvent event) {
        boolean checked = ((CheckBox) event.getTarget()).isSelected();
        for (Term term : terms) {
            term.setChecked(checked);
        }
    }

    @FXML
    public void handleRemoveAction(ActionEvent event) {
        Iterator<Term> iter = terms.iterator();
        while (iter.hasNext()) {
            Term term = iter.next();
            if (term.getChecked()) {
                iter.remove();
            }
        }
        resetTermsPn();
    }

    private boolean containTerm(String uid) {
        for (Term term : terms) {
            if (term.getTermUid().equals(uid)) {
                return true;
            }
        }
        return false;
    }

    public List<Term> getSelectedTerms() {
        return terms.stream().filter(Term::getChecked).collect(Collectors.toList());
    }

    private boolean checkOptCondition() {
        List<Term> selectedTerms = getSelectedTerms();
        if (selectedTerms.isEmpty()) {
            Dialogs.create().title("提示").message("请先选择要操作的单灯控制器").showInformation();
            return false;
        }
        SerialSession session = serialHandler.getSession(SerialPortFactory.PORT_TEST);
        if (session == null) {
            Dialogs.create().title("提示").message("请先打开串口").showInformation();
            return false;
        }
        return true;
    }

    @FXML
    public void handlePowerOnAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }

        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);
                for (Term term : getSelectedTerms()) {
                    if (!session.isConnected() || session.isClosing()) {
                        System.out.println("退出操作");
                        break;
                    }
                    System.out.println("正在开启" + term.getTermUid() + ", " + term.getPn());
                    session.dimmingLamp(100, CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException ignored) {
                    }
                    System.out.println();
                }
                return null;
            }
        };
        ExecutorsUtils.getInstance().execute(task);
    }

    @FXML
    public void handlePowerOffAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }

        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);
                for (Term term : getSelectedTerms()) {
                    if (!session.isConnected() || session.isClosing()) {
                        System.out.println("退出操作");
                        break;
                    }
                    System.out.println("正在关闭" + term.getTermUid() + ", " + term.getPn());
                    session.dimmingLamp(0, CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException ignored) {
                    }
                    System.out.println();
                }
                return null;
            }
        };
        ExecutorsUtils.getInstance().execute(task);
    }

    @FXML
    public void handleDimmingAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }

        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);
                for (Term term : getSelectedTerms()) {
                    if (!session.isConnected() || session.isClosing()) {
                        System.out.println("退出操作");
                        break;
                    }
                    System.out.println("正在调光" + term.getTermUid() + ", " + term.getPn());
                    session.dimmingLamp(getDimming(), CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException ignored) {
                    }
                    System.out.println();
                }
                return null;
            }
        };
        ExecutorsUtils.getInstance().execute(task);
    }

    @FXML
    public void handleQueryAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }

        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);
                for (Term term : getSelectedTerms()) {
                    if (!session.isConnected() || session.isClosing()) {
                        System.out.println("退出操作");
                        break;
                    }
                    System.out.println("正在查询数据, " + term.getTermUid() + ", " + term.getPn());
                    LampData lampData = session.readLampData(CONCENT_UID, term.getTermUid());
                    if (lampData == null) {
                        System.out.println("查询数据失败");
                    } else {
                        term.setLampData(lampData);
                        Term term1 = new Term();
                        terms.add(term1);
                        terms.remove(term1);
                    }
                    System.out.println();
                }
                return null;
            }
        };
        ExecutorsUtils.getInstance().execute(task);
    }


    @FXML
    public void handleOperationAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }

        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);
                for (Term term : getSelectedTerms()) {
                    if (!session.isConnected() || session.isClosing()) {
                        System.out.println("退出操作");
                        break;
                    }

                    System.out.println("一键操作" + term.getTermUid() + ", " + term.getPn());

                    System.out.println("1.开启");
                    session.dimmingLamp(100, CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("2.查询");
                    LampData lampData = session.readLampData(CONCENT_UID, term.getTermUid());
                    if (lampData == null) {
                        System.out.println("查询数据失败");
                    } else {
                        term.setLampData(lampData);
                        Term term1 = new Term();
                        terms.add(term1);
                        terms.remove(term1);
                    }

                    System.out.println("3.调光" + getDimming() + "%");
                    session.dimmingLamp(getDimming(), CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("4.关闭");
                    session.dimmingLamp(0, CONCENT_UID, term.getTermUid());
                    try {
                        Thread.sleep(getTimeout());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println();
                }
                return null;
            }
        };
        ExecutorsUtils.getInstance().execute(task);
    }

    @FXML
    public void handleDownloadAction(ActionEvent event) {
        if (!checkOptCondition()) {
            return;
        }
        Task<Boolean> task = new Task<Boolean>() {

            @Override
            protected Boolean call() throws Exception {
                BaseTestSession session = (BaseTestSession) serialHandler.getSession(SerialPortFactory.PORT_TEST);

                // 首先进行参数初始化
                System.out.println("参数初始化");
                boolean success = session.clearArchive();
                if (success) {
                    System.out.println("开始下发档案");

                    final int MAX_DOWNLOAD = 25;

                    List<Term> terms = getSelectedTerms();
                    int size = terms.size();
                    int num = size / MAX_DOWNLOAD + (size % MAX_DOWNLOAD == 0 ? 0 : 1);
                    System.out.println("共分" + num + "次下发");

                    for (int i = 0; i < num; i++) {
                        System.out.println("下发第" + i + "批档案");

                        int start = i * MAX_DOWNLOAD;
                        int end = ((i + 1) < num) ? (i + 1) * MAX_DOWNLOAD : size;
                        // 本次要下发的档案
                        List<Term> concentTerms = terms.subList(start, end);

                        int count = 0;
                        do {
                            if (count > 0) {
                                System.out.println("第" + count + "次重试");
                            }
                            success = session.downloadArchive(concentTerms);
                        } while (!success && count++ <= 3);

                        if (!success) {
                            return false;
                        }
                    }
                } else {
                    return false;
                }

                return true;
            }

            @Override
            protected void succeeded() {
                try {
                    System.out.println(get() ? "下发档案成功" : "下发档案失败");
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        };
        ExecutorsUtils.getInstance().execute(task);
        Dialogs.create().masthead(null).title("提示").message("正在下发档案中").showWorkerProgress(task);
    }

    public long getTimeout() {
        return (int) intervalSpinner.getValue() * 1000;
    }

    public int getDimming() {
        return (int) dimmingSpinner.getValue();
    }


}
